#include "job.h"
#include "getvoltages.h"

//persistJobHolder persistJobs;			// global declaration

Job::Job(string taskname)
// old constructor remove when new one works
{
	opt.fromMathematica(stdlink);
	sendmessage("entering base job constructor","",opt.getL("messagelevel"));
	sendmessage("Here are the options: \\\\n",opt.toString("\\\\n","\\\\t"),opt.L["messagelevel"]);
//	pjh.clearFinishedJobs();
	iErr = DAQmxCreateTask (taskname.c_str(), &taskHandle);
	checkerr(iErr,opt.getL("messagelevel"));	
}
Job::Job(string taskname, persistJobHolder &pjh)
// new constructor remove when new one works
{
	opt.fromMathematica(stdlink);
	sendmessage("entering New base job constructor","",opt.getL("messagelevel"));
	sendmessage("Here are the options: \\\\n",opt.toString("\\\\n","\\\\t"),opt.L["messagelevel"]);
	pjh.clearFinishedJobs();
	iErr = DAQmxCreateTask (taskname.c_str(), &taskHandle);
	checkerr(iErr,opt.getL("messagelevel"));	
}
Job::Job(string taskname, persistJobHolder &pjh, option& optOld) : opt(optOld)
// copy option reference
{
	sendmessage("entering  base job constructor that copies options","",opt.getL("messagelevel"));
	sendmessage("Here are the options: \\\\n",opt.toString("\\\\n","\\\\t"),opt.L["messagelevel"]);
	pjh.clearFinishedJobs();
	
	string chanStr = opt.getS("channels");
	std::replace(chanStr.begin(), chanStr.end(), '/', 'X');  // from algorithm
	std::replace(chanStr.begin(), chanStr.end(), ',', 'Y');  // from algorithm
//	std::cout << "chanStr : " << chanStr << std::endl;	
	taskname += chanStr;	
	iErr = DAQmxCreateTask (taskname.c_str(), &taskHandle);
	checkerr(iErr,opt.getL("messagelevel"));	
}
Job::Job(Job& old) : taskHandle(old.getTaskHandle()), opt(old.getOptions())
{
	old.clearTaskHandle();
}

Job::~Job()
{
// sending message is problematic beacuse mathlink is closed after data is returned;
// No point sending messages unless scope of Job in samller
//	sendmessage("Base class Job destructor called","",opt.getL("messagelevel"));
//	sendmessage("base dtor taskhandle = ",(long) taskHandle,opt.getL("messagelevel"));
	// Clear Task when destructor called is ok becaused cloned objects will hold task
	// and the original will only have taskHandle set to zero.
	if (taskHandle !=0)
	{
		iErr = DAQmxClearTask(taskHandle);
//		checkerr(iErr,getoptL("messagelevel"));
	}
//	checkerr(iErr,getoptL("messagelevel"));	

}

int Job::startTask(TaskHandle th)
{
	sendmessage("in Job::startTask taskHandle is : ", (long) th ,getoptL("messagelevel"));
	iErr = DAQmxStartTask(th);
	checkerr(iErr,opt.getL("messagelevel"));
	return iErr;
}
void Job::continueTask(double arg1, double arg2)
{
	sendmessage("Job::continueTask should be overridden","!!!",getoptL("messagelevel"));
}
void Job::configureClock(double numPeriods)
{
	sendmessage("configure clock for AI or AO voltage chan","!",getoptL("messagelevel"));
	iErr = DAQmxCfgSampClkTiming (getTaskHandle(),
		getoptS("clock").c_str(),
		getoptD("frequency"),
		getoptL("activeedge"),
		getoptL("samplemode"),
		(long) getoptL("samples") * numPeriods	// intentional rounding to allow fractional periods
		);
	checkerr(iErr,getoptL("messagelevel"));
	return;
}

InputJob::InputJob(string taskname) : Job(taskname)
{
	// old constructor remove when other functions converted
	sendmessage("inside OLD InputJob constructor","",getoptL("messagelevel"));
	sendmessage("messagelevel is ", getoptL("messagelevel"), getoptL("messagelevel"));
	sampleArraySize = getoptL("samples") * getoptL("numchannels");
	sampleArray = new double[sampleArraySize];
	createAIChan();
}
InputJob::InputJob(string taskname, persistJobHolder& pjh) : Job(taskname, pjh)
{
	// new constructor
	sendmessage("inside NEW InputJob constructor","",getoptL("messagelevel"));
	sendmessage("messagelevel is ", getoptL("messagelevel"), getoptL("messagelevel"));
	sampleArraySize = getoptL("samples") * getoptL("numchannels");
	sampleArray = new double[sampleArraySize];
	createAIChan();
}
InputJob::InputJob(string taskname, persistJobHolder& pjh, option& optOld) : Job(taskname, pjh, optOld)
{
	// new constructor
	sendmessage("inside NEW InputJob constructor","",getoptL("messagelevel"));
	sendmessage("messagelevel is ", getoptL("messagelevel"), getoptL("messagelevel"));
	sampleArraySize = getoptL("samples") * getoptL("numchannels");
	sampleArray = new double[sampleArraySize];
	createAIChan();
}

InputJob::InputJob(InputJob& old) : Job(old)
// options should be initialized in Job copy constructor
{
	sampleArraySize = getoptL("samples") * getoptL("numchannels");
	sampleArray = new double[sampleArraySize];
	for(int i =0; i < sampleArraySize; i++)					// probably don't need to copy elements
		*(sampleArray + i) = *(old.getSampleArray() + i);
	// let destructor of old cleanup old
}
InputJob::~InputJob()
{
// sending message is problematic beacuse mathlink is closed after data is returned;
//	sendmessage("inside InputJob dtor","",getoptL("messagelevel"));
	delete [] sampleArray;
}
void InputJob::continueTask(double arg1, double arg2)
{
	sendmessage("InputJob continuing Taskhandle = ",(long) getTaskHandle(),getoptL("messagelevel"));
//	isDoneNoError();
	readData();
	sendToMathematica();
	return;
}
void InputJob::createAIChan()
{
	sendmessage("creating AI voltage chan","!",getoptL("messagelevel"));
	iErr=DAQmxCreateAIVoltageChan(getTaskHandle(),
		getoptS("channels").c_str(),
		NULL,
		getoptL("terminalmode"),
		getoptD("min"),
		getoptD("max"),
		getoptL("units"),
		NULL);
	checkerr(iErr,getoptL("messagelevel"));
	return;
}


int InputJob::readData()
{
//	bool32 fillMode = DAQmx_Val_GroupByChannel;
	bool32 fillMode = DAQmx_Val_GroupByScanNumber;		// changed to be consistent with continuous acquistions
	sendmessage("In readData, messagelevel= ", getoptL("messagelevel"), getoptL("messagelevel"));
	int32 sampsPerChanRead=0;							// a return value
	iErr = DAQmxReadAnalogF64(
		getTaskHandle(),
		getoptL("samples"),
		getoptD("timeout"),
		fillMode,
		sampleArray,
		sampleArraySize,
		&sampsPerChanRead,
		NULL
		);	
	checkerr(iErr,getoptL("messagelevel"));
//	DAQmxStopTask(getTaskHandle());				// should this be here stops automatically if reads autostart
	return 0;
}
bool InputJob::sendToMathematica()
{
	if (MLReady(stdlink))
	{
		MLNewPacket(stdlink);
		MLNewPacket(stdlink);		// second one didn't help
		MLPutString(stdlink,"An error occurred reading the MathLink Connection");
	}
	else
	{
//		What should single measurement return list of one element or Real Number
// 			What about a MaxFlatten Attribute??
//		sendmessage("sampleArraySize =", sampleArraySize,3);
//		if (getoptL("numchannels") == 1 && getoptL("samples") == 1)
//			MLPutReal(stdlink, sampleArray[0]);
//		else
			MLPutRealList(stdlink, sampleArray, sampleArraySize);
	}
//	MLPutString(stdlink,"All Done");
	return true;
}

BufferedInputJob::BufferedInputJob(string taskname, persistJobHolder& pjh) : InputJob(taskname, pjh)
{
	// new constructor
	sendmessage("inside bufferdInputJob constructor","",getoptL("messagelevel"));
	sendmessage("messagelevel is ", getoptL("messagelevel"), getoptL("messagelevel"));
	configureClock();
	setTransferMech();
}
BufferedInputJob::BufferedInputJob(string taskname, persistJobHolder& pjh, option& optOld) : InputJob(taskname, pjh, optOld)
{
	// new constructor
	sendmessage("inside buffered InputJob constructor","",getoptL("messagelevel"));
	sendmessage("messagelevel is ", getoptL("messagelevel"), getoptL("messagelevel"));
	configureClock();
	setTransferMech();
}
BufferedInputJob::BufferedInputJob(BufferedInputJob& old) : InputJob(old)
// options should be initialized in Job copy constructor
{
	; // no data members
}
BufferedInputJob::~BufferedInputJob()
{
// sending message is problematic beacuse mathlink is closed after data is returned;
//	sendmessage("inside InputJob dtor","",getoptL("messagelevel"));
	; // no data members
}
void BufferedInputJob::setTransferMech()
{
	sendmessage("setting Input transfermechanism = ","!", getoptL("messagelevel"));
	int32 mech =-1;

	iErr = DAQmxSetAIDataXferMech(
		getTaskHandle(),					
		getoptS("channels").c_str(),			// transfer mechanism must be same for all channels
		getoptL("transfermech")
		);
	checkerr(iErr, getoptL("messagelevel"));

	iErr = DAQmxGetAIDataXferMech(getTaskHandle(),"dev1/ai0",&mech);
	checkerr(iErr, getoptL("messagelevel"));
	sendmessage("setting Output transfermechanism ai0 == ", mech, getoptL("messagelevel"));
	iErr = DAQmxGetAIDataXferMech(getTaskHandle(),"dev1/ai1",&mech);
	checkerr(iErr, getoptL("messagelevel"));
	sendmessage("error number is ", iErr, getoptL("messagelevel"));
	sendmessage("setting input transfermechanism ai1 == ", mech, getoptL("messagelevel"));

	return;
}
void BufferedInputJob::continueTask(double arg1, double arg2)
{
	sendmessage("BufferedInputJob continuing Taskhandle = ",(long) getTaskHandle(),getoptL("messagelevel"));
	startTask(getTaskHandle());
	isDoneNoError();
	readData();
	sendToMathematica();
	return;
}
bool BufferedInputJob::isDoneNoError()
{
	sendmessage("In BufferedInputJob isDoneNoError, taskhandle= ", getoptL("taskHandle"), getoptL("messagelevel"));
	volatile bool32 taskDone = false;
	TaskHandle tH = getTaskHandle();
	volatile int iErr = 0;
	while(!taskDone && !iErr && !MLAbort)
	{
		iErr = DAQmxIsTaskDone (tH, (bool32*) &taskDone);
//		checkerr(iErr,5);
//		sendmessage("isTaskDone = ",taskDone,5);		// inner loop
//		sendmessage("MLAbort = ", MLAbort,5);
		if (MLAbort)
		{
			DAQmxClearTask(tH);
			MLNewPacket(stdlink);
			MLPutFunction(stdlink,"Abort",0);
			return false;
		}
	}
	if (iErr == 0)
		return true;
	return false;
}
SoftTrigJob::SoftTrigJob(string taskname, persistJobHolder& pjh) : BufferedInputJob(taskname, pjh)
{doConstruction();}
SoftTrigJob::SoftTrigJob(string taskname, persistJobHolder& pjh, option& tempOpts) : BufferedInputJob(taskname, pjh, tempOpts)
{doConstruction();}
void SoftTrigJob::doConstruction()
{
	pPreTrigArray = getSampleArray();		// really just renaming for convenience
	preTrigArraySize = getSampleArraySize();	// InputJob will delete array
	testingArraySize = 10000 * getoptL("numchannels");	// 10,000 if slow
	if (getoptD("frequency") > 9999)
		testingArraySize = 100000 * getoptL("numchannels");	// 100,000 if fast
	uInt32 postTrigArraySize = getoptL("numchannels") * getoptL("posttrigsamples");
	if (postTrigArraySize > testingArraySize)
		testingArraySize = postTrigArraySize;
	else
		testingArraySize = postTrigArraySize + testingArraySize;
	pTestingArray = new float64[testingArraySize];
	readPastTrig = 0;
	return;
}
SoftTrigJob::SoftTrigJob(SoftTrigJob& old) : BufferedInputJob(old)
{
	readPastTrig = old.readPastTrig;
	pPreTrigArray = old.getSampleArray();
	preTrigArraySize = old.getSampleArraySize();
	testingArraySize = old.testingArraySize;			// even though private I can get at them in
	pTestingArray = new float64[testingArraySize];		// the copy constructor?
	for(long i=0; i < testingArraySize; i++)
		pTestingArray[i] = old.pTestingArray[i];
}
SoftTrigJob::~SoftTrigJob()
{
	delete [] pTestingArray;				// input job will clean up pretrigger array
}
long SoftTrigJob::waitForTrigger()
{
	sendmessage("inside wait for trig","!",5);
	bool32	taskDone = false;
	bool32 fillMode = DAQmx_Val_GroupByScanNumber;
	int32 sampsPerChanRead=0;
	bool triggerenabled = false, triggered = false;
	iErr = 0;
	uInt32 numavail=0;
	uInt64 totalsamples=0;
	while(!taskDone && !iErr && !triggered && !MLAbort)
	{
		iErr = DAQmxIsTaskDone (getTaskHandle(), &taskDone);
//		checkerr(iErr,5);
		iErr = DAQmxReadAnalogF64 (getTaskHandle(), -1, getoptD("timeout"), fillMode, \
		pTestingArray, testingArraySize, &sampsPerChanRead, NULL);
//		checkerr(iErr,5);
//		sendmessage("pretrigger value read = ",pPreTrigArray[0]);
		for(int i=0,j=0; i < sampsPerChanRead; i++, j += getoptL("numchannels"))
		{
		if (pTestingArray[j] < getoptD("triggerlevel"))
			triggerenabled = true;
		if (triggerenabled && pTestingArray[j] > getoptD("triggerlevel"))
			{
			triggered = true;
			readPastTrig = sampsPerChanRead - i;
			break;
			}
		}
	}
	return readPastTrig;
}
void SoftTrigJob::readPreTrigger()
{
	bool32 fillMode = DAQmx_Val_GroupByScanNumber;			// make class data memeber?
	uInt64 readPosition=0;
	int32 sampsPerChanRead=0;
	long  preTrigOffset = getoptL("pretrigsamples")+ readPastTrig;
	DAQmxGetReadCurrReadPos(getTaskHandle(),&readPosition);
	if (readPosition < preTrigOffset)
	{
		preTrigOffset = readPosition;
		preTrigArraySize = (readPosition-readPastTrig) * getoptL("numchannels");
	}

	iErr = DAQmxSetReadOffset(getTaskHandle(), -1*preTrigOffset);
	checkerr(iErr, getoptL("messagelevel"));
	iErr = DAQmxReadAnalogF64 (getTaskHandle(), -1, getoptD("timeout"), fillMode, \
			pPreTrigArray, preTrigArraySize, &sampsPerChanRead, NULL);
	checkerr(iErr, getoptL("messagelevel"));
}
void SoftTrigJob::readPostTrigger()
{
	int index = 0;
	bool32 fillMode = DAQmx_Val_GroupByScanNumber;			// make class data memeber?
	uInt32 postTrigArraySize = getoptL("numchannels") * getoptL("posttrigsamples");
	int32 sampsPerChanRead=0;
	DAQmxSetReadOffset(getTaskHandle(), 0); 
	index += sampsPerChanRead;
	iErr = DAQmxReadAnalogF64 (getTaskHandle(), -1, getoptD("timeout"), fillMode, \
			pTestingArray, postTrigArraySize, &sampsPerChanRead, NULL);

	DAQmxSetReadOffset(getTaskHandle(), 0);
	while(!iErr && index < getoptL("posttrigsamples"))
	{
		index += sampsPerChanRead;
		iErr = DAQmxReadAnalogF64 (getTaskHandle(), -1, getoptD("timeout"), fillMode, \
				pTestingArray + index * getoptL("numchannels"), postTrigArraySize*50, \
				&sampsPerChanRead, NULL);
//		sendmessage("Posttrigger samples read = ", sampsPerChanRead);
	}

	checkerr(iErr, getoptL("messagelevel"));

//	sendmessage("readpasttrig on the last testing pass = ", readpasttrig,opt.L["messagelevel"]);
//	sendmessage("Total number recorded before trigggering = ",(long) totalsamples,opt.L["messagelevel"]);	
//	sendmessage("readposition = ",(long) readPosition,opt.L["messagelevel"]);
//	sendmessage("preTrigOffset = ",(long) preTrigOffset,opt.L["messagelevel"]);
}
bool SoftTrigJob::sendToMathematica()
{
	uInt32 postTrigArraySize = getoptL("numchannels") * getoptL("posttrigsamples");
	MLPutFunction(stdlink,"List",2);
		MLPutRealList(stdlink,pPreTrigArray,preTrigArraySize);
		MLPutRealList(stdlink,pTestingArray,postTrigArraySize);
	return true;
}
// needs triggersorce and triggerslope in the options
DigitalTrigJob::DigitalTrigJob(string taskname, persistJobHolder& pjh) : BufferedInputJob(taskname, pjh)
{	doConstruction();}
DigitalTrigJob::DigitalTrigJob(string taskname, persistJobHolder& pjh, option& tempOpts) : BufferedInputJob(taskname, pjh, tempOpts)
{doConstruction();}
void DigitalTrigJob::doConstruction()
{
	sendmessage("Entering DigitalTrigJob constructor","!",getoptL("messagelevel"));
	iErr = DAQmxCfgDigEdgeStartTrig(getTaskHandle(),getoptS("triggersource").c_str(),getoptL("triggerslope"));		// digital triggering
	checkerr(iErr,getoptL("messagelevel"));
return;
}
DigitalTrigJob::DigitalTrigJob(DigitalTrigJob& old) : BufferedInputJob(old)
{		//no data memebers
}
DigitalTrigJob::~DigitalTrigJob()
{		// noting special input job does the cleanup
}


OutputJob::OutputJob(string taskname, persistJobHolder &pjh) : Job(taskname, pjh)
{doConstruction();}
OutputJob::OutputJob(string taskname, persistJobHolder &pjh, option& tempOptions) : Job(taskname, pjh, tempOptions)
{doConstruction();}

void OutputJob::doConstruction()
{
	dataStorage[0] = 0.0;
	dataStorage[1] = 0.0;
	sendmessage("inside new OutputJob constructor","",getoptL("messagelevel"));
	sendmessage("messagelevel is ", getoptL("messagelevel"), getoptL("messagelevel"));
	createAOChan();
//	configureClock(getoptD("numperiods"));		// need samples to be samples*numperiods for output only
//	setTransferMech();
//	waveformToBuffer();
}
OutputJob::OutputJob(OutputJob& old) : Job(old)
{
	dataStorage[0] = old.dataStorage[0];
	dataStorage[1] = old.dataStorage[1];
	// job copy constructor clears the old taskhandle
}

OutputJob::~OutputJob()
{
	//sending message is problematic beacuse mathlink is closed after data is returned;
//	sendmessage("inside OutputJob dtor","",getoptL("messagelevel"));
		;
}

void OutputJob::continueTask(double ch0Volt, double ch1Volt)
{
	dataStorage[0] = ch0Volt;
	dataStorage[1] = ch1Volt;
	writeData();
	MLPutSymbol(stdlink,"Null");
}
void OutputJob::writeData()
{
	bool32 autoStart = false;
	int32 written;
	sendmessage("writedata = dataStorage[0] = ", dataStorage[0], getoptL("messagelevel"));
	sendmessage("writedata = dataStorage[1] = ", dataStorage[1], getoptL("messageLevel"));
	iErr = DAQmxWriteAnalogF64(
		getTaskHandle(),
		1,				//better be 1
		autoStart,
		getoptD("timeout"),
		DAQmx_Val_GroupByChannel,		// change?
		dataStorage,
		&written,
		NULL);
	checkerr(iErr, getoptL("messagelevel"));
	return;
}

bool OutputJob::sendToMathematica()
{
	if (MLReady(stdlink))
	{
		MLNewPacket(stdlink);
		MLNewPacket(stdlink);		// second one didn't help
		MLPutString(stdlink,"An error occurred reading the MathLink Connection");
	}
	else
	{
//		sendmessage("sampleArraySize =", sampleArraySize,3);
		MLPutLongInteger(stdlink, (long) getTaskHandle());
	}
	return true;
}
void OutputJob::createAOChan()
{
	sendmessage("creating AO voltage chan","!",getoptL("messagelevel"));
	iErr=DAQmxCreateAOVoltageChan(getTaskHandle(),
		getoptS("channels").c_str(),
		NULL,
//		getoptL("terminalmode"),
		getoptD("min"),
		getoptD("max"),
		getoptL("units"),
		NULL);
	checkerr(iErr,getoptL("messagelevel"));
	return;
}

BufferedOutputJob::BufferedOutputJob(string taskname, persistJobHolder& pjh) : OutputJob(taskname, pjh)
{ doConstruction();}

BufferedOutputJob::BufferedOutputJob(string taskname, persistJobHolder& pjh, option& tempOpts) : OutputJob(taskname, pjh, tempOpts)
{doConstruction();}

BufferedOutputJob::BufferedOutputJob(BufferedOutputJob& old) : OutputJob(old)
{	;// no data members
}

BufferedOutputJob::~BufferedOutputJob()
{	; // nothing special to do
}
void BufferedOutputJob::doConstruction()
{
	configureClock(getoptD("numperiods"));		// need samples to be samples*numperiods for output only
	setTransferMech();
	waveformToBuffer();
}
void BufferedOutputJob::setTransferMech()
{
	sendmessage("setting output transfermechanism = ","!", getoptL("messagelevel"));
	int32 mech = -1;

	iErr = DAQmxSetAODataXferMech(
		getTaskHandle(),
		getoptS("channels").c_str(),			// more than one chan ok? yes all chans must have same transfer mech
		getoptL("transfermech")
		);
	checkerr(iErr, getoptL("messagelevel"));

// *** need to fix this to just check the channels being changed or defined
//	uInt32 bufSize=200;
//	char chans[200];
//	iErr = DAQmxGetTaskChannels(getTaskHandle(),chans,bufSize);
//	sendmessage("Output task number", chans, getoptL("messagelevel")+5);

//	iErr = DAQmxGetAODataXferMech(getTaskHandle(),"dev1/ao0",&mech);
//	checkerr(iErr, getoptL("messagelevel"));
//	sendmessage("setting Output transfermechanism ao0 == ", mech, getoptL("messagelevel"));
//	iErr = DAQmxGetAODataXferMech(getTaskHandle(),"dev1/ao1",&mech);
	checkerr(iErr, getoptL("messagelevel"));
	sendmessage("error number is ", iErr, getoptL("messagelevel"));
	sendmessage("setting Out transfermechanism ao1 == ", mech, getoptL("messagelevel"));
	return;
}
void BufferedOutputJob::waveformToBuffer()
{
	bool autoStart = false;
	int32 written;
	iErr = DAQmxWriteAnalogF64(
		getTaskHandle(),
		getoptL("samples"),
		autoStart,
		getoptD("timeout"),
		DAQmx_Val_GroupByChannel,		// change?
		getoptDArray("waveform"),
		&written,
		NULL);
	checkerr(iErr, getoptL("messagelevel"));
	return;
}
void BufferedOutputJob::continueTask(double ch0Volt, double ch1Volt)
{
	bool32 ans = false;
	DAQmxStopTask(getTaskHandle());
	int iErr = DAQmxIsTaskDone(getTaskHandle(),&ans);
	checkerr(iErr,getoptL("messagelevel"));
	sendmessage("Is buffered text done ",ans,getoptL("messagelevel"));
	startTask(getTaskHandle());
	MLPutSymbol(stdlink,"Null");
}

persistJobHolder::~persistJobHolder()
{
	for(map<TaskHandle, JobState>::iterator ip = jobList.begin(); ip != jobList.end(); ++ip)
		delete ip->second.pJob;
}
Job& persistJobHolder::changeToPersist(Job &old, long runAgainCount)
{
//	m.okToCopy = true;			// do I want this check
	TaskHandle th = old.getTaskHandle();
	jobList[th].runAgainCount = runAgainCount;
	jobList[th].pJob = old.clone();
	return *(jobList[th].pJob);
}
void persistJobHolder::clearJob(TaskHandle task)
{
	sendmessage("in clear task id is ",(long)task, jobList[task].pJob->getoptL("messagelevel"));
	delete jobList[task].pJob;			// call objects destructor
	jobList.erase(jobList.find(task));
}
void persistJobHolder::clearFinishedJobs()
{	
//	sendmessage("Entering persistjobholder clear finished jobs","!",5);  not associtated with an one job's message level
	typedef map<TaskHandle, JobState>::iterator jobList_iter;
	jobList_iter ip = jobList.begin();
	while(ip != jobList.end())
	{
		bool32 taskDone = false;
		jobList_iter old = ip;
		ip++;
		TaskHandle task = old->second.pJob->getTaskHandle();
		int iErr = DAQmxIsTaskDone(task, &taskDone);
//		sendmessage("in persistjob task id is ",(long)task,ip->second.pJob->getoptL("messagelevel");
//		checkerr(iErr, 5);
		if (old->second.runAgainCount == 0 && taskDone)
		{	
			delete old->second.pJob;
			jobList.erase(old);
		}
	}
//	sendmessage("Exiting persistjobholder clear finished jobs","!",5);
}




